﻿Public Class CrateManager

    Private FilesDataGridViewContextMenu As New ContextMenu
    Private CratesTreeViewContextMenu As New ContextMenu

    Private Crates As New List(Of Crate)
    Private ds As New CrateManagerDatabaseDataSet
    Private dtaFiles As New CrateManagerDatabaseDataSetTableAdapters.FilesTableAdapter
    Private RootNode As New TreeNode("Crates")

#Region "Application Event Handlers"

    ''' <summary>
    ''' Add an event handler for Application.Idle
    ''' </summary>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
        MyBase.OnLoad(e)
        AddHandler Application.Idle, AddressOf Application_Idle
    End Sub

    ''' <summary>
    ''' Temporary Event Handler. We use this to set up.
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub Application_Idle(ByVal sender As Object, ByVal e As EventArgs)

        ' Init GUI
        RemoveHandler Application.Idle, AddressOf Application_Idle
        ApplicationSplitContainer.Enabled = True

        ' Check Installation ID
        If My.Settings.InstallationID.ToString = "00000000-0000-0000-0000-000000000000" Then
            My.Settings.InstallationID = Guid.NewGuid
            My.Settings.Save()
        End If

        ' Check for valid root folder here
        If My.Settings.RootFolder = "" Or Not Directory.Exists(My.Settings.RootFolder) Then
            MsgBox("You need to set a root folder first!")
        End If

        ' Setup Context menus
        With FilesDataGridViewContextMenu.MenuItems
            .Add("Assign this track to crate", AddressOf Me.Assign_Click)
        End With
        With CratesTreeViewContextMenu.MenuItems
            .Add("Add new crate", AddressOf Me.NewCrateToolStripButton_Click)
        End With

        ' Load & Bind Data
        LoadFromDB()
        FilesDataGridView.DataSource = ds.Files.DefaultView
        CratesTreeView.Nodes.Add(RootNode)
        CratesTreeView.ExpandAll()

    End Sub

#End Region

#Region "Application Functions"

    ''' <summary>
    ''' Populate the DataSet from the Database and generate the treeview
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub LoadFromDB()

        ' Clear & load data
        ds.Files.Clear()
        dtaFiles.Fill(ds.Files)

        RootNode.Nodes.Clear()

        'TODO: Catch Exceptions here, in case root does not exist

        ' Loop through directories in root
        For Each dir As String In Directory.GetDirectories(My.Settings.RootFolder, "*", SearchOption.TopDirectoryOnly)

            Dim crateName As String = Path.GetFileName(dir)
            Dim re As New Regex(My.Settings.CratePrefix & "(\d+)")
            Dim ma As Match = re.Match(crateName)

            If ma IsNot Nothing And ma.Success = True Then
                Dim cr As New Crate
                cr.CrateName = crateName
                cr.CrateID = CInt(ma.Groups(1).Value)
                cr.CratePath = dir

                Crates.Add(cr)
                RootNode.Nodes.Add(Path.GetFileName(dir))

            ElseIf crateName = "Unassigned" Then
                RootNode.Nodes.Add(Path.GetFileName(dir))

            End If

        Next

        CratesTreeView.Sort()
        CratesTreeView.ExpandAll()

    End Sub

    ''' <summary>
    ''' Generate the PDF output document
    ''' </summary>
    ''' <param name="fileName"></param>
    ''' <remarks></remarks>
    Private Sub GeneratePDF(fileName As String)

        Using fs As New FileStream(fileName, FileMode.Create, FileAccess.ReadWrite)

            Dim document As New Document(PageSize.A4, 15, 15, 15, 15)
            Dim wri As iTextSharp.text.pdf.PdfWriter = iTextSharp.text.pdf.PdfWriter.GetInstance(document, fs)
            Dim fontBlack As iTextSharp.text.Font = New iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.HELVETICA, 7, iTextSharp.text.Font.ITALIC)
            Dim fontNormal As iTextSharp.text.Font = New iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.HELVETICA, 8, iTextSharp.text.Font.NORMAL)

            Dim fontBold As iTextSharp.text.Font = New iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.COURIER, 8, iTextSharp.text.Font.BOLD)

            document.Open()


            ds.Files.DefaultView.RowFilter = "CrateName LIKE 'CD%'"
            ds.Files.DefaultView.Sort = "CrateName, Filename"

            Dim dtb As DataTable = ds.Files.DefaultView.ToTable(True, {"CrateName"})

            Dim pdft As New PdfPTable(2)
            pdft.TotalWidth = 7.75 * 72
            pdft.HorizontalAlignment = Element.ALIGN_LEFT
            pdft.WidthPercentage = 100
            pdft.LockedWidth = True


            ' Loop through our distinct list of CD's
            Dim cdCell As PdfPCell
            Dim cdCounter As Integer = 0
            For Each row As DataRow In dtb.Rows

                cdCell = New PdfPCell
                Dim trackCounter As Integer = 1

                cdCell.Border = 1

                cdCounter += 1

                ds.Files.DefaultView.RowFilter = "CrateName = '" & row(0).ToString & "'"


                Dim cdTable As New PdfPTable(3)
                cdTable.WidthPercentage = 100
                cdTable.SetWidths({15, 10, 75})

                ' Loop tracks in this CD folder
                For Each trackRowView As DataRowView In ds.Files.DefaultView

                    Dim trackRow As FilesRow = CType(trackRowView.Row, FilesRow)


                    Dim indexCell As New PdfPCell
                    Dim imgCell As New PdfPCell
                    Dim txtCell As New PdfPCell

                    indexCell.Border = 0
                    imgCell.Border = 0
                    txtCell.Border = 0

                    txtCell.VerticalAlignment = Element.ALIGN_BOTTOM
                    indexCell.VerticalAlignment = Element.ALIGN_MIDDLE
                    imgCell.VerticalAlignment = Element.ALIGN_BOTTOM

                    indexCell.Padding = 1
                    imgCell.Padding = 1
                    txtCell.Padding = 1

                    If trackRow.Artist = "" Or trackRow.Title = "" Then
                        txtCell.AddElement(New Phrase(LT(trackRow.FileName, 40), fontNormal))
                    Else
                        Dim phraseTitle As New Phrase(LT(trackRow.Title, 40), fontNormal)
                        Dim phraseArtist As New Phrase(LT(trackRow.Artist, 40), fontBlack)

                        txtCell.AddElement(phraseTitle)
                        txtCell.AddElement(phraseArtist)
                    End If


                    Dim img As iTextSharp.text.Image
                    Try
                        img = iTextSharp.text.Image.GetInstance(BytesToImage(trackRow.MP3Image), Imaging.ImageFormat.Jpeg)
                    Catch ex As Exception
                        img = iTextSharp.text.Image.GetInstance(My.Resources.no_image, Imaging.ImageFormat.Jpeg)
                    End Try

                    img.ScaleAbsolute(20, 20)

                    indexCell.AddElement(New Phrase(row(0).ToString & ":" & trackCounter.ToString.PadLeft(2, CChar("0")), fontBold))
                    imgCell.AddElement(img)

                    cdTable.AddCell(indexCell)
                    cdTable.AddCell(imgCell)
                    cdTable.AddCell(txtCell)

                    trackCounter += 1

                Next

                cdCell.AddElement(cdTable)

                ' Add a final line break then add the cell to the table
                'cdCell.AddElement(New Phrase(vbCrLf, fontBlack))
                pdft.AddCell(cdCell)

            Next

            If cdCounter Mod 2 <> 0 Then
                Dim spacerCell As New PdfPCell
                spacerCell.Border = 0
                pdft.AddCell(spacerCell)
            End If


            document.Add(pdft)  ' Add the table
            fs.Flush()          ' Flush the stream
            document.Close()    ' Close the document

        End Using

        ds.Files.DefaultView.RowFilter = ""

    End Sub

#End Region

#Region "Helper Function"

    ''' <summary>
    ''' Trim Length and PAD  
    ''' </summary>
    ''' <param name="input"></param>
    ''' <param name="width"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function LT(input As String, width As Integer) As String
        LT = input.PadRight(width).Substring(0, width - 1)
    End Function

    ''' <summary>
    ''' Create an Image from a Byte()
    ''' </summary>
    ''' <param name="byteArray"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function BytesToImage(byteArray() As Byte) As Drawing.Image
        BytesToImage = Drawing.Image.FromStream(New MemoryStream(byteArray))
    End Function

    ''' <summary>
    ''' Create a Byte() from an Image
    ''' </summary>
    ''' <param name="image"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function ImageToBytes(image As Drawing.Image) As Byte()

        Dim ms As New MemoryStream

        If image IsNot Nothing Then
            image.Save(ms, Drawing.Imaging.ImageFormat.Jpeg)
        Else
            My.Resources.no_image.Save(ms, Drawing.Imaging.ImageFormat.Jpeg)
        End If

        ImageToBytes = ms.ToArray

    End Function

#End Region

#Region "GUI Event Handlers"

    ''' <summary>
    ''' Event Handler. Scan Folder Click.
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub ScanFolderToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles ScanFolderToolStripMenuItem.Click

        ' Loop files
        For Each f As String In IO.Directory.GetFiles(My.Settings.RootFolder, "*.mp3", IO.SearchOption.AllDirectories)

            Dim filePathArrary() As String = Path.GetDirectoryName(f).Split(CChar("\"))
            Dim crate As String = filePathArrary.Last
            Dim fileName As String = Path.GetFileNameWithoutExtension(f)
            Dim artist As String = ""
            Dim title As String = ""
            Dim img As Drawing.Image = My.Resources.no_image

            Try
                Dim mp3 As New Mp3Lib.Mp3File(f)
                title = mp3.TagHandler.Title
                artist = mp3.TagHandler.Artist
                img = mp3.TagHandler.Picture

            Catch ex As NotImplementedException

            End Try


            ds.Files.AddFilesRow(f, crate, fileName, artist, title, ImageToBytes(img))

        Next

        dtaFiles.Update(ds.Files)

        FilesDataGridView.DataSource = ds.Files.DefaultView
        FilesDataGridView.Columns(0).Width = 500

    End Sub

    ''' <summary>
    ''' Event Handler. Generate a PDF Document.
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub GeneratePDFToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles GeneratePDFToolStripMenuItem.Click

        Dim sfd As New SaveFileDialog
        sfd.Filter = "PDF Files (*.pdf) | *.pdf"
        sfd.FileName = "TrackListing.pdf"

        If sfd.ShowDialog = Windows.Forms.DialogResult.OK Then
            GeneratePDF(sfd.FileName)
        End If

    End Sub

    ''' <summary>
    ''' TreeView event handler.
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub trvFolderStructure_AfterSelect(sender As Object, e As System.Windows.Forms.TreeViewEventArgs) Handles CratesTreeView.AfterSelect
        ds.Files.DefaultView.RowFilter = "CrateName = '" & e.Node.Text & "'"
    End Sub

    ''' <summary>
    ''' Event Handler. Hide the column if its 0,1 or 5
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub FilesDataGridView_ColumnAdded(sender As Object, e As System.Windows.Forms.DataGridViewColumnEventArgs)
        If e.Column.Index = 0 Or e.Column.Index = 2 Or e.Column.Index = 5 Then e.Column.Visible = False
    End Sub

    ''' <summary>
    ''' Event Handler. Exit!
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub ExitToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles ExitToolStripMenuItem.Click
        Me.Close()
    End Sub

    ''' <summary>
    ''' Event Handler. Handle the drap 'n' drop
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub FilesDataGridView_DragDrop(sender As Object, e As System.Windows.Forms.DragEventArgs)
    End Sub

    ''' <summary>
    ''' Event Handler. Show right click context menu.
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub FilesDataGridView_MouseUp(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles FilesDataGridView.MouseUp

        Dim mySender As DataGridView = CType(sender, DataGridView)
        Dim hti As DataGridView.HitTestInfo

        If e.Button = Windows.Forms.MouseButtons.Right Then
            hti = mySender.HitTest(e.X, e.Y)
            If hti.Type = DataGridViewHitTestType.Cell Then

                Dim row As DataGridViewRow = mySender.Rows(hti.RowIndex)
                If row.Selected = False Then

                    ' If this row is not selected, then clear other selected rows, and select this one
                    mySender.ClearSelection()
                    row.Selected = True

                End If

                FilesDataGridViewContextMenu.Show(mySender, New Point(e.X, e.Y))

            End If

        End If

    End Sub

    ''' <summary>
    ''' Event Handler. 
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub Assign_Click(sender As Object, e As EventArgs)

        Dim crd As New CratesDialog
        crd.CratesListBox.DataSource = Crates
        crd.CratesListBox.DisplayMember = "CrateName"
        crd.CratesListBox.ValueMember = "CrateName"

        If crd.ShowDialog = Windows.Forms.DialogResult.OK Then

            ' Move the files

            For Each sRow As DataGridViewRow In FilesDataGridView.SelectedRows
                Try
                    Dim newName As String = My.Settings.RootFolder & "\" & CStr(crd.CratesListBox.SelectedValue) & "\" & Path.GetFileName(CStr(sRow.Cells(0).Value))
                    Trace.WriteLine(newName)

                Catch ex As IO.IOException

                End Try
            Next

        End If

        crd.Dispose()

    End Sub

    ''' <summary>
    ''' Event Handler. 
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub FilesDataGridView_SelectionChanged(sender As Object, e As System.EventArgs) Handles FilesDataGridView.SelectionChanged

        If FilesDataGridView.SelectedRows.Count > 0 Then

            Dim fName As String = CStr(FilesDataGridView.SelectedRows(0).Cells(0).Value)

            Try
                Dim mp3 As New Mp3Lib.Mp3File(fName)
                With mp3.TagHandler
                    AlbumLabel.Text = .Album
                    ArtistLabel.Text = .Artist
                    CommentLabel.Text = .Comment
                    ComposerLabel.Text = .Composer
                    DiscLabel.Text = .Disc
                    GenreLabel.Text = .Genre
                    MP3ImageTagPictureBox.Image = .Picture
                    TitleLabel.Text = .Title
                    TrackLabel.Text = .Track
                End With

            Catch ex As NotImplementedException
                AlbumLabel.Text = ""
                ArtistLabel.Text = ""
                CommentLabel.Text = ""
                ComposerLabel.Text = ""
                DiscLabel.Text = ""
                GenreLabel.Text = ""
                MP3ImageTagPictureBox.Image = My.Resources.no_image
                TitleLabel.Text = ""
                TrackLabel.Text = ""

            Catch ex As IOException
                MsgBox("Something is amiss here. Couldn't access file: " & fName)

            End Try


        End If

    End Sub

    ''' <summary>
    ''' Event Handler. Create new crate.
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub NewCrateToolStripButton_Click(sender As System.Object, e As System.EventArgs) Handles NewCrateToolStripButton.Click

    End Sub

#End Region

End Class